package liuyao.webutils.utils;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 二维码工具类
 **/
public class QRCodeUtils {

    public static final String CHARSET = "utf-8";

    public static String analyze(MultipartFile file) {
        try {
            return analyze(file.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    public static String analyze(InputStream inputStream) {
        BufferedImage image;
        try {
            image = ImageIO.read(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        }
        return analyze(image);
    }

    public static String analyze(String path) {
        BufferedImage image;
        try {
            image = ImageIO.read(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        }
        return analyze(image);
    }

    /**
     * 解析二维码
     */
    public static String analyze(BufferedImage image) {
        image = ImageOptimizationUtil.binarization(image);
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        Binarizer binarizer = new HybridBinarizer(source);
        BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
        Map<DecodeHintType, Object> hints = new HashMap<>();
        //设置编码格式
        hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
        MultiFormatReader de = new MultiFormatReader();
        try {
            return de.decode(binaryBitmap, hints).getText();
        } catch (NotFoundException e) {
            e.printStackTrace();
			//这里判断如果识别不了带LOGO的图片，重新添加上一个属性
            try {
				//设置优化精度
				hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
				//设置复杂模式开启（我使用这种方式就可以识别微信的二维码了）
				hints.put(DecodeHintType.PURE_BARCODE, Boolean.TYPE);
				return de.decode(binaryBitmap, hints).getText();
			} catch (NotFoundException e1) {
                e1.printStackTrace();
				return e1.getMessage();
			}
        }
    }


    public static BitMatrix generate(String contents) throws WriterException {
        // 定义二维码的参数
        HashMap hints = new HashMap();
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET); // 定义字符集编码格式
        hints.put(EncodeHintType.MARGIN, 2); // 设置图片边距
        // 纠错的等级 L > M > Q > H 纠错的能力越高可存储的越少，一般使用M
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        return new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, 200, 200, hints);
    }

    public static OutputStream generate(String contents, OutputStream os) throws WriterException, IOException {
        // 图片的格式
        String format = "png";
        BitMatrix bitMat = generate(contents);
        MatrixToImageWriter.writeToStream(bitMat, format, os);
        return os;
    }

    public static String generateBase64(String contents) throws WriterException, IOException {
        // 图片的格式
        String format = "png";
        BitMatrix bitMat = generate(contents);
        BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMat);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(image, "png", stream);
        byte[] byteArray = stream.toByteArray();
        return Base64.getEncoder().encodeToString(stream.toByteArray());
    }
}